import { Feature } from 'ol';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import Point from 'ol/geom/Point';
import { Fill, Stroke, Style } from 'ol/style';
import { Kriging } from './kriging';
import { isobands, featureCollection, intersect, polygon as turfPolygon } from '@turf/turf';
import { GeoJSON } from 'ol/format';
/**
 * 等值面工具类，用于基于点数据生成等值面图层
 * 使用克里金插值算法和Turf.js的等值面生成功能
 */
export class Isosurfaces {
    /**
     * 构造函数，初始化等值面工具
     * @param {Map} map - OpenLayers地图实例
     * @param {OlUtil} olutil - OlUtil工具类实例
     */
    constructor(map, olutil) {
        Object.defineProperty(this, "map", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        }); // OpenLayers地图实例
        Object.defineProperty(this, "olutil", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: null
        }); // OlUtil工具类实例
        Object.defineProperty(this, "selectedFeatures", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: []
        }); // 选中的要素集合
        Object.defineProperty(this, "pointArr", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: []
        }); // 点数据数组
        /**设置传入的点数据
         * @param {Array<Object>} pointArr - 点数据数组，包含x,y坐标和z值
         */
        Object.defineProperty(this, "setPointArr", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: (pointArr) => {
                if (!this.map || !this.olutil)
                    return;
                this.pointArr = pointArr;
            }
        });
        /**
         * 计算并生成等值面图层
         * 1. 创建临时矢量图层
         * 2. 使用克里金插值算法生成网格数据
         * 3. 使用Turf.js生成等值面
         * 4. 将结果添加到地图
         * @param {Array<Object>} _pointArr - 点数据数组，包含x,y坐标和z值
         * @param {Object} _params - 参数对象，包含克里金模型、测量误差方差、克里金模型参数、等值面颜色数组、网格密度和裁剪区域等
         * @returns {VectorLayer|void} - 异步操作完成后返回Promise
         */
        Object.defineProperty(this, "computeIsosurfaces", {
            enumerable: true,
            configurable: true,
            writable: true,
            value: (_pointArr, _params) => {
                this.setPointArr(_pointArr);
                if (!this.map || !this.olutil)
                    return;
                const defalutParams = {
                    krigingModel: 'exponential', // 克里金模型类型 'gaussian' - 高斯模型 'exponential' - 指数模型 'spherical' - 球面模型
                    krigingSigma2: 0.01, // 测量误差方差(通常设置在 0.1 到 10 之间，值越小表示对原始数据的拟合越精确（可能过拟合）值越大表示允许更多平滑（可能欠拟合）)
                    krigingAlpha: 0.5, // 克里金模型参数 值越大表示空间相关性衰减越快（影响范围小） 值越小表示空间相关性衰减越慢（影响范围大）
                    colors: [
                        'rgba(230, 245, 224, 0.9)', // 微量降雨 (浅绿)
                        'rgba(161, 217, 155, 0.9)', // 小雨 (绿)
                        'rgba(102, 189, 99, 0.9)', // 中雨 (深绿)
                        'rgba(65, 182, 196, 0.9)', // 中到大雨 (蓝绿)
                        'rgba(66, 165, 245, 0.9)', // 大雨 (蓝)
                        'rgba(100, 149, 237, 0.9)', // 暴雨 (深蓝)
                        'rgba(147, 112, 219, 0.9)', // 大暴雨 (蓝紫)
                        'rgba(186, 104, 200, 0.9)', // 特大暴雨 (紫)
                        'rgba(171, 71, 188, 0.9)', // 极端降雨 (深紫)
                        'rgba(142, 36, 170, 0.9)' // 超强降雨 (紫红)
                    ],
                    gridDensity: 100, // 网格密度 (每米的格点数)
                    province: [], // 裁剪区域
                    id: 'isosurfaces', // 矢量图层ID
                    valueField: 'value' // 点位数值的字段名称
                };
                const params = Object.assign({}, defalutParams, _params);
                let WFSVectorSource = new VectorSource();
                let WFSVectorLayer = new VectorLayer({
                    source: WFSVectorSource
                });
                this.map.addLayer(WFSVectorLayer);
                let pointArr;
                if (this.pointArr && this.pointArr.length > 0) {
                    pointArr = this.pointArr;
                }
                else {
                    pointArr = [
                        { x: 87.62, y: 43.83, z: 5 }, // 小雨
                        { x: 87.63, y: 43.84, z: 15 }, // 中雨
                        { x: 87.61, y: 43.82, z: 2 }, // 毛毛雨
                        { x: 87.625, y: 43.835, z: 25 }, // 中到大雨
                        { x: 87.615, y: 43.825, z: 40 }, // 大雨
                        { x: 87.64, y: 43.85, z: 60 }, // 暴雨
                        { x: 87.6, y: 43.8, z: 80 }, // 大暴雨
                        { x: 87.635, y: 43.845, z: 100 }, // 特大暴雨
                        { x: 87.605, y: 43.815, z: 120 }, // 极端降雨
                        { x: 87.645, y: 43.855, z: 150 } // 超强降雨
                    ];
                }
                // 构造面数据
                for (let i = 0; i < pointArr.length; i++) {
                    let feature = new Feature({
                        geometry: new Point([pointArr[i].x, pointArr[i].y]),
                        value: pointArr[i][params.valueField]
                    });
                    WFSVectorSource.addFeature(feature);
                }
                let extent = WFSVectorLayer.getSource().getExtent();
                WFSVectorSource.forEachFeatureIntersectingExtent(extent, (feature) => {
                    this.selectedFeatures.push(feature);
                });
                // 计算等值面
                let values = [], lngs = [], lats = [];
                this.selectedFeatures.forEach((feature) => {
                    values.push(feature.values_.value);
                    lngs.push(feature.values_.geometry.flatCoordinates[0]);
                    lats.push(feature.values_.geometry.flatCoordinates[1]);
                });
                const kriging = new Kriging();
                let variogram = kriging.train(values, lngs, lats, params.krigingModel, params.krigingSigma2, params.krigingAlpha);
                let polygons = [];
                polygons.push([
                    [extent[0], extent[1]],
                    [extent[0], extent[3]],
                    [extent[2], extent[3]],
                    [extent[2], extent[1]]
                ]);
                let grid = kriging.grid(polygons, variogram, (extent[2] - extent[0]) / params.gridDensity); // 调整网格密度
                if (WFSVectorLayer !== null) {
                    this.map.removeLayer(WFSVectorLayer);
                }
                // 检查grid是否为有效对象
                if (!grid || typeof grid !== 'object' || !grid.list || !Array.isArray(grid.list)) {
                    console.error('Invalid grid data:', grid);
                    return;
                }
                // 获取最大和最小值
                const minValue = Math.min(...values);
                const maxValue = Math.max(...values);
                // 根据值获取颜色
                function getColorForValue(value, minValue, maxValue) {
                    const numValue = Math.round(parseFloat(value.split('-')[1]));
                    // 确保index在合理范围内
                    const index = Math.min(Math.max(0, Math.floor(((numValue - minValue) / (maxValue - minValue)) * params.colors.length)), params.colors.length - 1);
                    return params.colors[index] || params.colors[0]; // 默认返回第一个颜色
                }
                let vectorSource = new VectorSource();
                WFSVectorLayer = new VectorLayer({
                    zIndex: 10,
                    source: vectorSource,
                    style: function (feature) {
                        const value = feature.get('value');
                        // 根据值设置不同颜色
                        const color = getColorForValue(value, minValue, maxValue);
                        return new Style({
                            fill: new Fill({
                                color: color
                            }),
                            // 使用与填充色相同的颜色避免相邻区域出现黑边
                            stroke: new Stroke({
                                color: color.replace(/[\d\.]+\)$/, '1)'), // 移除透明度
                                width: 0.5 // 使用更细的线宽
                            })
                        });
                    }
                });
                // 直接使用grid数据创建点网格
                const features = grid.list
                    .map((row, rowIndex) => {
                    return row.map((value, colIndex) => {
                        const x = extent[0] + (colIndex * (extent[2] - extent[0])) / (row.length - 1);
                        const y = extent[1] + (rowIndex * (extent[3] - extent[1])) / (grid.list.length - 1);
                        return {
                            type: 'Feature',
                            geometry: {
                                type: 'Point',
                                coordinates: [x, y]
                            },
                            properties: {
                                value: value
                            }
                        };
                    });
                })
                    .flat();
                const pointGridData = {
                    type: 'FeatureCollection',
                    features: features
                };
                // 确保断点与数据范围匹配
                let breaks = [];
                for (let i = 0; i <= 10; i++) {
                    breaks.push(minValue + ((maxValue - minValue) * i) / 10);
                }
                let _isobands = isobands(pointGridData, breaks, { zProperty: 'value' });
                let polyFeatures;
                if (!params.province || params.province.length === 0) {
                    polyFeatures = new GeoJSON().readFeatures(_isobands, {
                        featureProjection: 'EPSG:4326'
                    });
                }
                else {
                    const clippedFeatures = _isobands.features
                        .map((feature) => {
                        const provinceFeature = turfPolygon([params.province]);
                        const clipped = intersect(featureCollection([feature, provinceFeature]));
                        if (clipped) {
                            clipped.properties = feature.properties;
                        }
                        return clipped;
                    })
                        .filter(Boolean); // 过滤掉null结果
                    const _clippedFeatures = {
                        type: 'FeatureCollection',
                        features: clippedFeatures
                    };
                    polyFeatures = new GeoJSON().readFeatures(_clippedFeatures, {
                        featureProjection: 'EPSG:4326'
                    });
                }
                vectorSource.addFeatures(polyFeatures);
                WFSVectorLayer.set('id', params.id);
                this.map.addLayer(WFSVectorLayer);
                return WFSVectorLayer;
            }
        });
        this.map = map;
        this.olutil = olutil;
    }
}
